﻿/**
 * @file cfg.h
 * @author septem (jsm920@outlook.com)
 * @brief 用于读写 cfg 文件, 以C语言来编写。"
 * @version 0.0.1
 * @date 2024-10-13
 * 
 * @copyright Copyright (c) 2024
 * @note cfg配置文件定义
 * 1. 注释 （与C++相同）
 * 1.1 整行注释 // 
 *  从 // 起直到回车 注释一整行
 * 1.2 多行注释 \/* *\/ 与C++ 相同
 *  从 \/* *\/ 注释全部，禁止 嵌套
 * 2. 数值类型：
 * 2.1 纯数值类型 pure-value
 *  纯数值类型结构 以类型开始，中间加 : 后面加数据; 例如 str:"这是一个字符串类型的数据", int8:32, int8:'a',
 *  当忽略类型时 各种大类型有默认值 
 * 2.1.1 字符串类型，以 "" 包括的类型，默认类型为 str 
 *  多个仅以空格或制符表分隔的视为一个字符串，例 "a" "b" estr:"\n" str:"b" 相当于 estr:"ab\nc"
 *  多行字符串可以在尾部加上 \ 变为一行字符串,例：
 * "abc "\
 * "def"
 * 相当于 "abc def"
 * 2.1.1.1 str 简单字符串类型，默认类型;以 "" 包括的类型，不允许包含转义字符，例 str:"这是一个简单字符串类型"
 * 2.1.1.2 estr 带有转义的字符串类型，以 "" 包括的类型，允许包含转义字符，例 estr:"带有\"转义\"的字符串类型"
 *  转义字符说明：
 *  <table>
 *      <caption>转义字符</caption>
 *      <tr><th>转义字符</th><th>意义</th><th>ASCII码值（十进制/八进制/十六进制/二进制/符号/HTML 编号）</th></tr>
 *      <tr><td>\a</td><td>响铃(BEL)</td><td>7/007/07/00000111/BEL/&#007;</td></tr>
 *      <tr><td>\b</td><td>退格(BS) ，将当前位置移到前一列</td><td>8/010/08/00001000/BS/&#008;</td></tr>
 *      <tr><td>\f</td><td>换页(FF)，将当前位置移到下页开头</td><td>12/014/0C/00001100/FF/&#012;</td></tr>
 *      <tr><td>\n</td><td>换行(LF) ，将当前位置移到下一行开头</td><td>10/012/0A/00001010/LF/&#010;</td></tr>
 *      <tr><td>\r</td><td>回车(CR) ，将当前位置移到本行开头</td><td>13/015/0D/00001101/CR/&#013;</td></tr>
 *      <tr><td>\t</td><td>水平制表(HT) （跳到下一个TAB位置）</td><td>9/011/09/00001001/HT/&#009;</td></tr>
 *      <tr><td>\V</td><td>垂直制表(VT)</td><td>11/013/0B/00001011/VT/&#011;</td></tr>
 *      <tr><td>\\</td><td>代表一个反斜线字符"\"</td><td>92/134/5C/01011100/\/&#92;</td></tr>
 *      <tr><td>\'</td><td>代表一个单引号（撇号）字符</td><td>39/047/27/00100111/'/&#39;</td></tr>
 *      <tr><td>\"</td><td>代表一个双引号字符</td><td>34/042/22/00100010/"/&#34;</td></tr>
 *      <tr><td>\?</td><td>代表一个问号</td><td>63/077/3F/00111111/?/&#63;</td></tr>
 *      <tr><td>\0</td><td>空字符(NUL)</td><td>0/000/00/00000000/NUL/&#000;</td></tr>
 *      <tr><td>\ooo</td><td>表示一个八进制值，其中 ooo 是一到三个八进制数字。例如，\101 表示字符 'A'。</td><td>三位八进制</td></tr>
 *      <tr><td>\xhh</td><td>表示一个十六进制值，其中 hh 是一个或多个十六进制数字。例如，\x41 表示字符 'A'。</td><td>十六进制</td></tr>
 *      <tr><td>\uhhhh</td><td>UTF16BE编码，hhhh这十六进制的UTF16BE编码</td><td>UTF16BE编码</td></tr>
 *  </table>
 * 2.1.1.2 base64 BASE64编码字符串类型，以 "" 包括的类型，内部保存为 二进制串，仅打印时显示 base64
 * 2.1.2 整型，默认类型为 int
 * 2.1.2.1 int 十进制整型,结构为 [+]/d{1,}|-/d{1,} ，例 121, -123,+135
 * 2.1.2.2 uint 十进制整型,结构为 [+]/d{1,}|-/d{1,} ，例 121 
 * 2.1.2.2 int8 十进制整型,结构为 [+]/d{1,3}|-/d{1,3}|'[a-zA-z0-9]'|'\0'|'\'' ，例 121, -123,+135，int8:'a',int8:'\'',int8:'\0'
 * 2.1.2.6 uint8 十进制整型,结构为 /d{1,3}|'[a-zA-z0-9]'|'\0'|'\'' ，例 121, -123,+135，int8:'a',int8:'\'',int8:'\0'
 * 2.1.2.3 int16 十进制整型,结构为 [+]/d{1,5}|-/d{1,5} ，例 121, -123,+135，int16:32767
 * 2.1.2.7 uint16 十进制整型,结构为 /d{1,5} ，例 121,+135，int16:32767
 * 2.1.2.4 int32 十进制整型,结构为 [+]/d{1,10}|-/d{1,10} ，例 121, -123,+135，int16:32767,int16:2147483647
 * 2.1.2.8 uint32 十进制整型,结构为 /d{1,10} ，例 121,135，int16:32767,int16:2147483647
 * 2.1.2.5 int64 十进制整型,结构为 [+]/d{1,19}|-/d{1,19} ，例 121, -123,+135，int32:+32767,int32:9223372036854775807
 * 2.1.2.9 uint64 十进制整型,结构为 /d{1,19} ，例 121,135，int32:32767,int32:9223372036854775807
 * 2.1.3 bin 二进制，以 0b 或 0B 开头的 0和1组成的数据
 * 2.1.4 otc 二进制，以 0 开头的 0~7 组成的数据
 * 2.1.5 hex 二进制，以 0x 开头的 0~9ABCDEF或0~9abcdef 组成的数据
 * 2.1.6 float 浮点类型 保存为 double
 * 2.1.7 complex 类型 real 和 imag 部分均为单精度浮点
 * 2.1.8 bool 布尔类型 (true|false)赋值时使用 true / false 
 * 2.2 key-vlue 键值对 name = pure-value | array | group 键值对 以名称 = 纯数值类型|array|array|group 为结构, 名称不允许使用 类型字符串， 不使用 "" 包括
 * 2.3 array 数组 以 [] 仅包括 pure-value， 例 array:[1,"a", str"a", estr:"\'"]
 * 2.3 group 键值对数组 以 {} 仅包括 键值对， 例 group:{a=1,b=str:"a", c=str"a", d=estr:"\'",e =(),f=[],g={}}
 * 2.5 set 集合， 以 set:() 与 array 相似，但数据不能重复，如果重复就会忽略
 * 2.6 map 键值对 以 map:{} 与 group 相似，但数据不能重复，如果重复就会忽略
 * 3. 特殊指令
 *  #include "file.cfg"
 */
#ifndef _HEAD_CFG_
#define _HEAD_CFG_
#define CFG_VER_MAJOR    0
#define CFG_VER_MINOR    0
#define CFG_VER_REVISION 1

#if defined(_WIN32) && defined(_MSC_VER)
// #pragma execution_character_set("utf-8")
#define WIN32_LEAN_AND_MEAN // 预处理器宏定义，它告诉编译器仅包含Windows SDK中最常用的函数和数据类型，从而减小编译时间和生成的可执行文件大小。
#pragma warning(disable : 4996) // 关闭使用 posix 函数的告警
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#elif defined(__linux__)
#include <stdio.h>
#endif
#include "array.h" // 提供 stack 数据结构功能
#include "tree.h"  // 提供 tree 数据结构功能

#ifndef DebugPrintf
#ifndef NDEBUG
#if defined(_WIN32) && defined(_MSC_VER)
#define DebugPrintf(format,...) printf(format,__VA_ARGS__),fflush(stdout)
#elif defined(__linux__)
#define DebugPrintf(format,...) printf(format,__VA_ARGS__)
#endif
#else
#define DebugPrintf(format,...) 
#endif
#endif
/**
 * @brief 定义 cfg 配置的类型见 @ref cfgiguration-File-Grammar "http://hyperrealm.github.io/libcfgig/libcfgig_manual.html#cfgiguration-File-Grammar"
 * 
 */
enum cfgtype_e
{
    CFG_TYPE_ROOT = 0x7fff, // 根类型
    CFG_TYPE_NULL = 0x0000,  // 表示空值 形如 null 
    CFG_TYPE_COMMENT= 0x0100, // 注释 形如 //
    CFG_TYPE_COMMENT_MULTILINE= 0x0101, // 注释 形如 /*
    CFG_TYPE_GROUP = 0x0210,  // 键值对集合（键值对指name=value），用 {} 括起来的以 , 分隔 
    CFG_TYPE_ARRAY = 0x0220,  // 值集合(值指value)，用 [] 括起来 以 , 分隔的 纯值集合， 
    CFG_TYPE_INT = 0x0600, // 整型，占用8个字节。形如 ...-2,-1,0,+1,1,+2,2....
    CFG_TYPE_INT8 = 0x0601, // 整形，占用1个字节。范围[-128,127],形式如 CFG_TYPE_INT
    CFG_TYPE_INT16 = 0x0602, // 整形，占用2个字节。范围[−32768,32767],形式如 CFG_TYPE_INT
    CFG_TYPE_INT32 = 0x0603, // 整形，占用4个字节。范围[−2147483648,2147483647],形式如 CFG_TYPE_INT
    CFG_TYPE_INT64 = 0x0600,  // 整形，占用8个字节。范围-9223372036854775808,9223372036854775807],形式如 CFG_TYPE_INT
    CFG_TYPE_UINT = 0x0620, // 无符号整型，占用8个字节。形如0，1,2...
    CFG_TYPE_UINT8 = 0x0621,// 无符号整形，占用1个字节。范围[0,255],形式如 CFG_TYPE_UINT
    CFG_TYPE_UINT16 = 0x0622,// 无符号整形，占用2个字节。范围[0,65535],形式如 CFG_TYPE_UINT
    CFG_TYPE_UINT32 = 0x0623, // 无符号整形，占用4个字节。范围[0,4294967295],形式如 CFG_TYPE_UINT
    CFG_TYPE_UINT64 = 0x0620, // 无符号整形，占用8个字节。范围[0,18446744073709551615],形式如 CFG_TYPE_UINT
    CFG_TYPE_BOOL = 0x0630, // 布尔型 true或false
    CFG_TYPE_FLOAT = 0x0640,// 浮点数(在此处为双精度浮点，占用8个字节，与C语言中的double相同)
    CFG_TYPE_COMPLEX = 0x0650, // 复数，中间不能有空格，必须有实部和i虚部纯值数据类型 浮点数，float保存 例 +1+i+2
    CFG_TYPE_STR = 0x0a00, // 字符串,不包含转义字符,形如 "string",'string',str:"string",str:'string'
    CFG_TYPE_ESTR = 0x0a01, // 带转义字符的字符串,转义之后读入内存。形如 `estring`,estr:"string",estr:'string', 
    CFG_TYPE_BASE64 = 0x0a02, // BASE64编码字符串，转换为二进制读入内存。
    CFG_TYPE_HEX = 0x0a03, // HEX编码字符串，转换为二进制读入内存，中间可以用 ' ' 或 '\t' 分隔
};

#define CfgTypeIsRoot(type) ((type) == CFG_TYPE_ROOT) //检查容器是否是 root
#define CfgTypeIsContainer(type) (((type) & 0xFF00) == (CFG_TYPE_GROUP & 0xFF00))  // 检查是否是容器
#define CfgTypeIsKVContainer(type) (((type) & 0xFFF0) == (CFG_TYPE_GROUP & 0xFFF0))  // 检查是否是键值对容器
#define CfgTypeIsVContainer(type) (((type) & 0xFFF0) == (CFG_TYPE_ARRAY & 0xFFF0))  // 检查是否是键值对容器
#define CfgTypeIsComment(type)  (((type)&0xFF00) == CFG_TYPE_COMMENT) // 检查是否是注释

#define MAX_PARSE_BUF 1024 * 10  //分析数据时最大的分配大小 最大大小 10 KB

/** 正在分析的阶段 */
enum cfgparsestage_e
{
    CFG_PARSE_STAGE_NONE = 0, //无正在进行的内容
    CFG_PARSE_STAGE_KEYVALUE_KEY = 0x2100, //读取到一个变量
    CFG_PARSE_STAGE_KEYVALUE_EQL = 0x2101, //读取到一个变量后面的等号
    CFG_PARSE_STAGE_KEYVALUE_TYPE = 0x2102, // 读取取一个变量后面的类型，等待读取 VALUE
    CFG_PARSE_STAGE_KEYVALUE_COLON = 0x2103, //读取到冒号
    CFG_PARSE_STAGE_KEYVALUE_VALUE = 0x2104, // 读取到变量后面的 VALUE, 但是 VALUE 跨越了缓存， 需要再次读取缓存。
    CFG_PARSE_STAGE_TYPE = CFG_PARSE_STAGE_KEYVALUE_TYPE, // 读取取一类型，等待读取 VALUE
    CFG_PARSE_STAGE_VALUE = CFG_PARSE_STAGE_KEYVALUE_VALUE, // 读取一个的 VALUE, 但是 VALUE 跨越了缓存， 需要再次读取缓存。
    CFG_PARSE_STAGE_COLON = CFG_PARSE_STAGE_KEYVALUE_COLON, //读取到冒号
    CFG_PARSE_STAGE_STR = CFG_TYPE_STR, //处于 字符串之中
    CFG_PARSE_STAGE_ESTR = CFG_TYPE_ESTR, //处于 字符串之中
    CFG_PARSE_STAGE_GROUP = CFG_TYPE_GROUP, // 正在读取 group 值, 子元素是值组
    CFG_PARSE_STAGE_GROUP_SEPARATOR, // group的分隔符,或;  
    CFG_PARSE_STAGE_ARRAY= CFG_TYPE_ARRAY, 
    CFG_PARSE_STAGE_ARRAY_SEPARATOR,// array的分隔符,或; 
    CFG_PARSE_STAGE_CONTENT = CFG_TYPE_COMMENT, //正在分析单行注释，
    CFG_PARSE_STAGE_CONTENT_MULTILINE = CFG_TYPE_COMMENT_MULTILINE //正在分析多行注释
};

/**
 * @brief 分析错误代码
 * 
 */
enum cfgerr_e
{
    CFG_ERR_SUCCESS = 0, 
    CFG_ERR_ADD_TREE_LEAF  =1, //向tree添加时发生错误
    CFG_ERR_ADD_STACK, // 向stack添加时发生错误
    CFG_ERR_MALLOC_KEY, //分配 key时出错
    CFG_ERR_CHAR, // 错误字符
    CFG_ERR_STR_HAS_LF = 100, // 字符串中有换行

    CFG_ERR_KV_NOT_KV = 200, // 要求键值对
    CFG_ERR_KV_NOT_EQUEL = 201, //键值对，应该是等号
    CFG_ERR_KV_ADDTO_NONCONTAINER, // 将键值对向非键值对容器插入
    CFG_ERR_V_ADDTO_NONCONTAINER, // 将值向非值容器插入
    CFG_ERR_GROUP_NOT_LBRACES = 400, // 要求 下一个字符是{ 
    CFG_ERR_GROUP_NOT_ELEM = 401, //要求是元素
    CFG_ERR_GROUP_NOT_SPLITTER, //要求是分隔符
    CFG_ERR_GROUP_LBRACES = 410, //
    CFG_ERR_NO_SPLITTER = 500,//

    CFG_ERR_ARRAY_NOT_BRACKETS = 600, // 要求下一个字符是[ 
    CFG_ERR_ARRAY_NOT_ELEM, //要求是元素
    CFG_ERR_ARRAY_NOT_SPLITTER,//要求是分隔符
};

/**
 * @brief 文本分析过程具体数据
 * 
 */
typedef struct cfgparsedata_t
{
    enum cfgparsestage_e stage; // 当前分析阶段
    enum cfgtype_e type; //当前正在分析的关键字类型
    unsigned int sposKey; //  key 开始时位置, 与 ftell() 结果相同
    unsigned int lenKey; //  key 结束时位置, 与 ftell() 结果相同
    unsigned int sposVal; //  value 开始时位置, 与 ftell() 结果相同
    unsigned int lenVal; //  value 结束时位置, 与 ftell() 结果相同
    union _VAL_u
    {
        long long llval; //  对于 group/array/set/map 此值表示 子元素数量
        double    fval;
        struct _cfgcomplex_t{
            float real;
            float imag;
        }cval; // 单精度复数
    }value;
    // unsigned int sline; //开始时行号，从1开始计数
    // unsigned int spos; // 开始位置 与 ftell结果相同
    // unsigned int eline; //结束时行号，从1开始计数
    // unsigned int epos; // 结束位置 与 ftell结果相同
    treenode_t*  parentNode; // 保存父节点
    treenode_t*  selfNode; //保存自身节点，用于 group\array\array\set\map,在以上类型向tree添加时修改，
}cfgparsedata_t;

/**
 * @brief 文本分析过程数据
 * 
 */
typedef struct cfgparse_t
{
    stack2_t stackParseData; // 分析过程 cfgparsedata_t 的数据栈
    // treestack_t stackCfgData; // 保存分析过程 cfgdata_t* 栈，用于回朔到父节点
    FILE* fp; //当前已打开的文本
    unsigned int bom:16; // BOM类型 0:EF BB BF	UTF-8;1:FE FF UTF16BE;2:FF FE UTF16LE;3:FF FE 00 00	UTF32LE;4:00 00 FE FF UTF32BE;255:no BOM
    unsigned int szBom:16;// BOM的长度
    char* pbuf; //已从文本中读取的待分析的部分文本
    unsigned int szPbuf; //分配的 pbuf 的大小
    unsigned int szBuf; //当前从文本中读取并保存在 cfgparse_t::pbuf 中的数量。
    unsigned posBuf; // 当前正在分析的 cfgparse_t::pbuf 的位置
    unsigned int line; //文件中当前行号 从 1 开始
    unsigned int pos; // 文件中当前位 字符序号（包含BOM） 从 0 开始，与 ftell() 一致
    unsigned int signReloadRead:1; //继续 调用 fread 从文件中读 
}cfgparse_t;

/**
 * @brief 数据键值对，通过分析文本所得
 * 
 */
typedef struct cfgdata_t
{
    enum cfgtype_e type; // 数据类型
    unsigned int klen; // key的长度，字节数，不是字符数,不包含 '\0',计算空间时需要加1
    unsigned int vlen; // value的长度，字节数，不是字符数,不包含 '\0'
    char* key; // 键名称，键名称可以为空
    /**
     * @brief linux x64:
     * sizeof(char*)==4,sizeof(char)==1,sizeof(short)==2,sizeof(int)==4, sizeof(long)==4, 
     * sizeof(long long)==8,sizeof(float)==4,sizeof(double)==8,sizeof(long double)==12,
     * 
     */
    union cfgvalue_u
    {
        long long llval; // 长整型整数
        double fval; // 双精度浮点数
        char *sval; // 字符串
        struct cfgdata_t *kv; // cfgdata_t 是键值对
        struct cfgcomplex_t{
            float real;
            float imag;
        }cval; // 单精度复数
    } value; //数据
}cfgdata_t;

/**
 * @brief cfg_t 配置结构
 * 
 */
typedef struct cfg_t
{
    tree_t*     ptRoot; // 树数据结构的数据，按结构保存分析所得的数据 cfgdata_t
    cfgparse_t parse;   // 正在分析的文本数据，由 CfgOpen() 初始化
    // cfgMap_t* root; //根元素
    // cfgMap_t* cur; //当前元素
    // cfgMap_t* prealloc;    // 预分配未使用的 cfgMap_t
    // cfgParse_t parse;
    // unsigned int memUsed; //当前 cfg_t 数据总使用内存总量，不包括预分配的量，仅包括已使用的量
    unsigned int signSaveComment:1; // 是否保存注释，默认保存
    // /** 错误报告 */
    struct _cfg_diagnosis_t
    {
        unsigned int err;
        unsigned int line;
        unsigned int pos;
    }diagnosis;
    // /** 打印格式 */
    // struct _cfg_format_t
    // {
    //     unsigned char tab;
    // }format;
    // unsigned int cntMap; // malloc 的 cfgMap_t 的数量
    
}cfg_t;
/**
 * @brief 计算 cfg_t 需要分配多少内存
 * 
 */
#define CfgMemUsed(cnt) sizeof(cfg_t) + TreeMemUsed(sizeof(cfgdata_t), cnt)

/**
 * @brief malloc 一个 cfg_t 预分配cfg_t 和 cntMap 个 cfgMap_t 数据
 * 
 * @param cnt 预分配 cnt 个 cfgdata_t 数据
 * @return cfg_t* 
 * @note 成功分配之后，如果不再使用请使用 cfg_free 注销
 */
cfg_t* CfgMalloc(unsigned int cnt);

cfg_t* CfgInit(cfg_t* pcfg, unsigned int cnt);
/**
 * @brief free 包括 cfg_t* 在内的所有内存，
 * 
 * @param pcfg 
 */
void CfgFree(cfg_t *pcfg);
/**
 * @brief free不包括 cfg_t* 的所有内存
 * 
 * @param pcfg 
 */
void CfgUninit(cfg_t *pcfg);

/**
 * @brief 打开一个文件用于分析
 * 
 * @param file 
 * @return FILE* 
 */
int CfgOpen(const char * file, cfg_t* pcfg );
int CfgCreate(const char * file );
int CfgClose(cfg_t* pcfg);

// /**
//  * @brief 用于遍历 cfg_t
//  * 
//  */
// typedef struct cfgiterator_t 
// {
//     cfg_t* pcfg;
//     treenode_t* pcd; //当前正在访问的对象 //  也是栈顶的元素
//     stack2_t stack; //保存访问序列，用于从子元素退回到父元素
// }cfgiterator_t;
// /**
//  * @brief 初始化 cfgiterator_t 指针,用于遍历 cfg_t
//  * 
//  * @param pcfg 
//  * @return cfgiterator_t* 
//  */
// cfgiterator_t* CfgPointerMalloc( cfg_t* pcfg);
// /**
//  * @brief 注销一个 cfgiterator_t
//  * 
//  * @param pcp 
//  */
// void CfgPointerFree(cfgiterator_t* pcp);
// /**
//  * @brief 获取当前元素的父元素，如果是root，返回NULL
//  * 
//  * @param pcp 
//  * @return cfgdata_t* 
//  */
// cfgdata_t* CfgPointerParent(cfgiterator_t* pcp);
// /**
//  * @brief 获取当前对象的第一个子元素
//  * 
//  * @param pcp 
//  * @return cfgdata_t* 
//  */
// cfgdata_t* CfgPointerChild(cfgiterator_t* pcp);
// /**
//  * @brief 获取当前对象的前一个兄弟元素
//  * 
//  * @param pcp 
//  * @return cfgdata_t* 
//  */
// cfgdata_t* CfgPointerBrotherPrev(cfgiterator_t* pcp);
// /**
//  * @brief 获取当前对象的后一个兄弟元素
//  * 
//  * @param pcp 
//  * @return cfgdata_t* 
//  */
// cfgdata_t* CfgPointerBrotherNext(cfgiterator_t* pcp);

// int CfgPointerGetType(cfgiterator_t* pcp);

// int CfgPointerIsRoot(cfgiterator_t* pcp);

// int CfgPointerIsStrs(cfgiterator_t* pcp);

// int CfgPointerIsInts(cfgiterator_t* pcp);

// int CfgPointerIsFloat(cfgiterator_t* pcp);

// int CfgPointerIsComplex(cfgiterator_t* pcp);

// char* CfgPointerGetStr(cfgiterator_t* pcp);

// int CfgPointerGetStrLen(cfgiterator_t* pcp);

// long long CfgPointerGetInt(cfgiterator_t* pcp);

// unsigned long long CfgPointerGetUint(cfgiterator_t* pcp);

// double CfgPointerGetFloat(cfgiterator_t* pcp);

// float* CfgPointerGetComplex(cfgiterator_t* pcp);


/**
 * @brief 读取并分析文件
 * 
 * @param pcfg 
 * @return int 
 */
int CfgParse(cfg_t* pcfg);
/**
 * @brief 向 pcfg 中的 where 插入一个 type 的 key:value , 当 value 为 str 一类的数据时 需要填写vlen，否则直到 '\0' 结束。当aschild为1时添加为兄弟元素
 * 
 * @param pcfg 
 * @param where 
 * @param aschild 
 * @param type 
 * @param key 
 * @param value 
 * @param vlen 
 * @return cfgMap_t* 
 */
// cfgMap_t* CfgSet(cfg_t* pcfg,cfgMap_t* where, int aschild, enum cfgKeywords type, char* key, void* value, unsigned int vlen);

cfgdata_t* CfgNodeData(treenode_t*);

treenode_t* CfgRoot(cfg_t* pcfg);

treenode_t* CfgNodePparent(treenode_t* node);

treenode_t* CfgNodeChild(treenode_t* node);

treenode_t* CfgNodeNext(treenode_t* node);

#endif // end of define _HEAD_CFG_


// cfgiguration File Grammar

// Below is the BNF grammar for cfgiguration files. Comments and include directives are not part of the grammar, so they are not included here.

// <cfgiguration> ::=
//       <setting-array>
//     | <empty>

// <setting-array> ::=
//       <setting>
//     | <setting-array> <setting>

// <setting> ::=
//       <name> ( ":" | "=" ) <value> ( ";" | "," | <empty> )

// <value> ::=
//       <scalar-value>
//     | <array>
//     | <array>
//     | <group>

// <value-array> ::=
//       <value>
//     | <value-array> "," <value>
//     | <value-array> ","

// <scalar-value> ::=
//       <boolean>
//     | <integer>
//     | <integer64>
//     | <hex>
//     | <hex64>
//     | <float>
//     | <string>

// <scalar-value-array> ::=
//       <scalar-value>
//     | <scalar-value-array> "," <scalar-value>
//     | <scalar-value-array> ","

// <array> ::=
//       "[" ( <scalar-value-array> | <empty> ) "]"

// <array> ::=
//       "(" ( <value-array> | <empty> ) ")"

// <group> ::=
//       "{" ( <setting-array> | <empty> ) "}"

// <empty> ::=



// Terminals are defined below as regular expressions:

// <boolean>/([Tt][Rr][Uu][Ee])|([Ff][Aa][Ll][Ss][Ee])
// <string>/\"([^\"\\]|\\.)*\"
// <name>/[A-Za-z\*][-A-Za-z0-9_\*]*
// <integer>/[-+]?[0-9]+
// <integer64>/[-+]?[0-9]+L(L)?
// <hex>/0[Xx][0-9A-Fa-f]+
// <hex64>/0[Xx][0-9A-Fa-f]+(L(L)?)?
// <float>/([-+]?([0-9]*)?\.[0-9]*([eE][-+]?[0-9]+)?)|([-+]([0-9]+)(\.[0-9]*)?[eE][-+]?[0-9]+)

